﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using CanPower.Achieve;
using CanPower.Models;
using static CanPower.Models.MainViewModel;

namespace CanPower.Achieve
{
    static class CANCommunitor
    {
        
        #region DllImport
        
        // 导入厂商提供的 Achieve/DLL/ControlCAN.dll 的方法
        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_OpenDevice(uint deviceType, uint deviceIndex, uint reserved);

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_CloseDevice(uint deviceType, uint deviceIndex);

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_InitCAN(
            uint deviceType,
            uint deviceIndex,
            uint canIndex,
            ref VCI_INIT_CONFIG config
        );

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_StartCAN(uint deviceType, uint deviceIndex, uint canIndex);

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_Transmit(
            uint deviceType,
            uint deviceIndex,
            uint canIndex,
            ref VCI_CAN_OBJ send,
            uint length
        );

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll")]
        public static extern int VCI_Receive(
            uint deviceType,
            uint deviceIndex,
            uint canIndex,
            [In, Out] VCI_CAN_OBJ[] recv,
            uint length,
            int waitTime
        );

        [DllImport("D:\\2025\\VS_Project\\CAN\\CanPower\\can\\Achieve\\DLL\\ControlCAN.dll", CharSet = CharSet.Ansi)]
        public static extern uint VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);

        // 定义初始化结构体
        [StructLayout(LayoutKind.Sequential)]
        public struct VCI_INIT_CONFIG
        {
            public uint AccCode;
            public uint AccMask;
            public uint Reserved;
            public byte Filter;
            public byte Timing0;
            public byte Timing1;
            public byte Mode;
        }

        // 定义 CAN 消息结构体
        [StructLayout(LayoutKind.Sequential)]
        public struct VCI_CAN_OBJ
        {
            public uint ID; // 29 位扩展帧 ID
            public uint TimeStamp; // 时间戳
            public byte TimeFlag; // 是否使用时间标志
            public byte SendType; // 发送帧类型
            public byte RemoteFlag; // 是否是远程帧
            public byte ExternFlag; // 是否是扩展帧
            public byte DataLen; // 数据长度

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] Data; // 数据

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public byte[] Reserved; // 保留位
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct VCI_BOARD_INFO1
        {
            public ushort hw_Version;
            public ushort fw_Version;
            public ushort dr_Version;
            public ushort in_Version;
            public ushort irq_Num;
            public byte can_Num;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string str_Serial_Num;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
            public string str_hw_Type;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public ushort[] Reserved;
        }

        public static uint GetDeviceCount()
        {
            VCI_BOARD_INFO1 deviceInfo = new VCI_BOARD_INFO1();
            uint deviceCount = VCI_FindUsbDevice(ref deviceInfo);

            if (deviceCount == 0)
            {
                Console.WriteLine("未找到任何设备");
            }
            else
            {
                Console.WriteLine($"找到 {deviceCount} 个设备：");
                Console.WriteLine($"  硬件版本: {deviceInfo.hw_Version}");
                Console.WriteLine($"  固件版本: {deviceInfo.fw_Version}");
                Console.WriteLine($"  驱动版本: {deviceInfo.dr_Version}");
                Console.WriteLine($"  接口版本: {deviceInfo.in_Version}");
                Console.WriteLine($"  CAN 通道数量: {deviceInfo.can_Num}");
                Console.WriteLine($"  序列号: {deviceInfo.str_Serial_Num}");
                Console.WriteLine($"  硬件类型: {deviceInfo.str_hw_Type}");
            }

            return deviceCount;
        }

        #endregion

        #region 包装方法

        private static VCI_INIT_CONFIG config = new VCI_INIT_CONFIG
        {
            AccCode = 0x00000000, // 验收码
            AccMask = 0xFFFFFFFF, // 屏蔽码
            Reserved = 0,
            Filter = 1, // 滤波器（1 = 单滤波）
            Timing0 = 0x03, // 波特率 125Kbps，Timing0 = 0x03，Timing1 = 0x1C
            Timing1 = 0x1C,
            Mode = 0 // 模式（0 = 正常模式）
        };

        #region 常量定义(模块基础信息)
        
        
        private static uint deviceType = 4; // 设备类型（CANalyst-II 通常是 4）

        private static uint deviceIndex = 0; // 设备索引

        private static uint canIndex = 0; // 通道号

        // private static CANDeviceInfo DeviceInfo;
        #endregion

        private static HashSet<string> sourceAddressNoList = new();

        private static List<string> ProductNoList;

        private static List<byte> ModuleAddresslist = new();

        private static volatile int CurrentCanIndex = -1;

        private static volatile int PublicCompleteFlag = -1;

        internal static readonly int CANDeviceCount = 15;

        internal static uint CANModuleCount { get; private set; }

        private static ConcurrentDictionary<int, bool> Status;

        private static ConcurrentDictionary<int, string> ProNo2ModuleIndex = new();

        private static ConcurrentDictionary<int, List<byte>> PowerNo2ModuleIndex = new();

        internal static ReadOnlyDictionary<int, string[]> PowerNo2ModuleAddress;

        private static bool[] CanModuleStatus;

        private static VCI_CAN_OBJ[] recvBuffer = new VCI_CAN_OBJ[50]; // 接收缓冲区，最多可接收 50 条消息

        public static bool OpenDevice()
        {
            if (VCI_OpenDevice(deviceType, deviceIndex, 0) == 0)
            {
                Console.WriteLine("设备打开失败");
                return true;
            }

            CANModuleCount = GetDeviceCount();

            //DeviceInfo = new();

            CanModuleStatus = new bool[CANModuleCount];

            // 初始化 CAN 配置
            VCI_INIT_CONFIG config = new VCI_INIT_CONFIG
            {
                AccCode = 0x00000000, // 验收码
                AccMask = 0xFFFFFFFF, // 屏蔽码
                Reserved = 0,
                Filter = 1, // 滤波器（1 = 单滤波）
                Timing0 = 0x03, // 波特率 125Kbps，Timing0 = 0x03，Timing1 = 0x1C
                Timing1 = 0x1C,
                Mode = 0 // 模式（0 = 正常模式）
            };

            return false;
        }

        public static bool CANDeviceInit()
        {
            return VCI_InitCAN(deviceType, deviceIndex, canIndex, ref config) == 0;
        }

        public static void StartReceiving()
        {
            var t = Task.Run(async () =>
            {
                VCI_CAN_OBJ[] recvBuffer = new VCI_CAN_OBJ[50]; // 接收缓冲区，最多可接收 50 条消息
                while (true)
                {
                    try
                    {
                        int receivedCount = VCI_Receive(
                            deviceType,
                            deviceIndex,
                            canIndex,
                            recvBuffer,
                            50,
                            100
                        );
                        if (receivedCount > 0)
                        {
                            for (int i = 0; i < receivedCount; i++)
                            {
#if DEBUG

                                Console.WriteLine($"消息 ID: {recvBuffer[i].ID:X}");
                                Console.WriteLine($"扩展帧: {recvBuffer[i].ExternFlag}");
                                Console.WriteLine($"远程帧: {recvBuffer[i].RemoteFlag}");
                                Console.WriteLine($"数据长度: {recvBuffer[i].DataLen}");
                                Console.Write("数据: ");
                                for (int j = 0; j < recvBuffer[i].DataLen; j++)
                                {
                                    Console.Write($"{recvBuffer[i].Data[j]:X2} ");
                                }
                                Console.WriteLine();

#endif

                                if (recvBuffer[i].Data[0] == 0x07)
                                {
                                    var tempSpan = recvBuffer[i].Data.Skip(2).Take(8 - 2).ToArray();

                                    sourceAddressNoList.Add(
                                        BitConverter.ToString(tempSpan).Replace("-", "")
                                    );
                                }
                                else if (
                                    recvBuffer[i].Data[0] == 0x03
                                    && recvBuffer[i].Data[3] == 0x0d
                                )
                                {
                                    ModuleAddresslist.Add(recvBuffer[i].Data[7]);
                                }
                                else if (
                                    recvBuffer[i].Data[0] == 0x01
                                    && recvBuffer[i].Data[3] == 0x0d
                                )
                                {
#if DEBUG
                                    Console.WriteLine(
                                        $"模块{BitConverter.ToString(recvBuffer[i].Data.Skip(4).Take(8 - 4).ToArray())}设置完成"
                                    );
#endif
                                }
                                else if (recvBuffer[i].Data[3] == 0x07)
                                {
#if DEBUG
                                    Console.WriteLine(
                                        $"模块{CurrentCanIndex}的电源状态为{(recvBuffer[i].Data[4] == 3 ? "关" : "开")}"
                                    );
#endif
                                    Interlocked.Exchange(ref PublicCompleteFlag, 1);
                                    Status[CurrentCanIndex] = recvBuffer[i].Data[4] == 0;
                                }
                                else if (recvBuffer[i].Data[3] == 0x21)
                                {
#if DEBUG
                                    Console.WriteLine($"模块{CurrentCanIndex}的电源写入行为收到反馈");
#endif
                                    Interlocked.Exchange(ref PublicCompleteFlag, 1);
                                }
                            }
                        }

                        await Task.Delay(50).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
#if DEBUG
                        Console.WriteLine($"Error: {ex.Message}");
#endif
                    }
                }
            });
        }

        public static bool StartCAN()
        {
            return VCI_StartCAN(deviceType, deviceIndex, canIndex) == 0;
        }

        //定位模块并获取模块地址，与配置文件的信息将模块地址与电源对应起来，将PowerNo2ModuleIndex填充完整
        public static async ValueTask InitAllInfo()
        {
            await sourceAddressNoList
                .WaitFor(
                    (source) =>
                    {
                        return source.Count == CANDeviceCount;
                    },
                    10000
                )
                .ContinueWith(
                    (_) =>
                    {
                        ProductNoList = sourceAddressNoList.ToList();
                        Status = new();
                    }
                );

            var temparray = new byte[] { 0x0a, 0x00 };

            try
            {
                //按照顺序给所有的Can模块设置模块地址
                for (int i = 0; i < ProductNoList.Count; i++)
                {
                    temparray[1] = (byte)(i + 1);

                    ProNo2ModuleIndex[i + 1] = ProductNoList[i];

                    SendMsg(
                        GetID(DestinationAddress: 0x00),
                        temparray.Concat(ProductNoList[i].Str2AddressNo()).ToArray()
                    );

                    var pair = PowerNo2ModuleAddress.First(x => x.Value.Contains(ProductNoList[i]));

                    if (!PowerNo2ModuleIndex.ContainsKey(pair.Key))
                    {
                        PowerNo2ModuleIndex[pair.Key] = new List<byte>();
                    }

                    PowerNo2ModuleIndex[pair.Key].Add(temparray[1]);

                    await Task.Delay(10).ConfigureAwait(false);
                }

                await PowerNo2ModuleIndex.WaitFor(
                    (_) =>
                    {
                        return PowerNo2ModuleIndex.Values.Sum(x => x.Count) == 15;
                    },
                    10000
                );

                temparray = new byte[] { 0x09, 0x00 };

                //读取所有模块的地址
                foreach (var item in ProductNoList)
                {
                    SendMsg(
                        GetID(DestinationAddress: 0x00),
                        temparray.Concat(item.Str2AddressNo()).ToArray()
                    );

                    await Task.Delay(10).ConfigureAwait(false);
                }

                //等待读取所有的模块地址
                await ModuleAddresslist.WaitFor(
                    (source) =>
                    {
                        return source.Count == 15;
                    },
                    100000
                );

                temparray = new byte[] { 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00 };

                //读取所有的电源模块开关状态
                foreach (var item in ModuleAddresslist)
                {
                    Interlocked.Exchange(ref CurrentCanIndex, item);

                    Interlocked.Exchange(ref PublicCompleteFlag, 0);

                    temparray[1] = item;

                    SendMsg(GetID(DestinationAddress: item), temparray);

                    await PublicCompleteFlag.WaitFor((_) => PublicCompleteFlag == 1, 10000);
                }

                await Status.WaitFor(
                    (source) =>
                    {
                        return source.Count == ProductNoList.Count;
                    },
                    10000
                );
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private static VCI_CAN_OBJ BuildSendMsg(uint id, byte[] data)
        {
            return new VCI_CAN_OBJ
            {
                ID = id, // 扩展帧 ID (29 位)
                ExternFlag = 1, // 标记为扩展帧
                RemoteFlag = 0, // 数据帧
                SendType = 0, // 正常发送
                DataLen = 8, // 数据长度
                Data = data,
                Reserved = new byte[3] // 保留
            };
        }

        public static bool SendMsg(uint id, byte[] data)
        {
            VCI_CAN_OBJ send = BuildSendMsg(id, data);
            return VCI_Transmit(deviceType, deviceIndex, canIndex, ref send, 1) == 0;
        }

        private static string GetBinaryString(int value, int bitCount)
        {
            var tempStr = Convert.ToString(value, 2);

            return tempStr.PadLeft(bitCount, '0');
        }

        private static uint GetID(
            int Protocol = 0x01,
            int SystemType = 0x02,
            int DestinationAddress = 0x0,
            int SourceAddress = 0xF0,
            int SerinalNumberLowPart = 0
        )
        {
            var tempStr =
                $"{GetBinaryString(Protocol, 2)}{GetBinaryString(SystemType, 5)}{GetBinaryString(DestinationAddress, 8)}{GetBinaryString(SourceAddress, 8)}{GetBinaryString(SerinalNumberLowPart, 6)}";

            return Convert.ToUInt32(tempStr, 2);
        }

        public static async ValueTask<bool> SetPower(int moduleIndex, bool power)
        {
            try
            {
                var moduleAddesss = PowerNo2ModuleIndex[moduleIndex];

                var data = new byte[]
                {
                    0x00,
                    0x00,
                    0x00,
                    0x21,
                    0x00,
                    0x00,
                    0x00,
                    power ? (byte)0x00 : (byte)0x01
                };

                foreach (var item in moduleAddesss)
                {
                    Interlocked.Exchange(ref CurrentCanIndex, item);

                    Interlocked.Exchange(ref PublicCompleteFlag, 0);

                    data[1] = item;

                    SendMsg(GetID(DestinationAddress: item), data);

                    await PublicCompleteFlag.WaitFor((_) => PublicCompleteFlag == 1, 10000);
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        public static async ValueTask<bool[]> GetPowerStatus()
        {
            var data = new byte[] { 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00 };

            foreach (var item in ModuleAddresslist)
            {
                Interlocked.Exchange(ref CurrentCanIndex, item);

                Interlocked.Exchange(ref PublicCompleteFlag, 0);

                data[1] = item;

                SendMsg(GetID(DestinationAddress: item), data);

                await PublicCompleteFlag.WaitFor((_) => PublicCompleteFlag == 1, 10000);
            }

            return PowerNo2ModuleIndex //电源与模块地址的对应关系
                .OrderBy(pair => pair.Key) //按照模块号排序
                .Select(pair => pair.Value.All(status => CanModuleStatus[status])) //按照模块号排序，并取出对应模块的电源状态
                .ToArray();
        }

        #endregion
    }
}
